﻿/*
 * slaverdm.cpp
 *
 *  Created on: 2017年5月17日
 *      Author: work
 */

#include "slaverdm.h"

#include <dm/os/log/logger.hpp>

#include <dm/os/msg/msgdriver.hpp>
#include <dm/os/protocol/protocolmaster.hpp>

#include <dm/datetime.hpp>

static const char* logModule = "CSlaver.dmsync.app";

CSlaverDm::CSlaverDm():dm::os::protocol::CProtocolSlaver(),m_callIndex(0),m_wait(false){
	log().debug(THISMODULE "创建对象");
	setRefreshInterval(100);
	m_waitTimeout = 10;
	m_clockInterval = 0;
	m_acceptClock = true;

	m_offset_s = 0;
	m_offset_d = 0;
	m_offset_m = 0;
	m_offset_c = 0;
	m_offset_r = 0;
	m_offset_p = 0;
	m_offset_a = 0;

	m_size_s = -1;
	m_size_d = -1;
	m_size_m = -1;
	m_size_c = -1;
	m_size_r = -1;
	m_size_p = -1;
	m_size_a = -1;

}

CSlaverDm::~CSlaverDm(){
	log().debug(THISMODULE "销毁对象");
}

const char* CSlaverDm::name()const{
	return "Dm Slaver";
}

CSlaverDm::frame_t& CSlaverDm::getRxFrame(){
	return m_rxFrame;
}

const CSlaverDm::frame_t& CSlaverDm::getTxFrame(){
	return m_txFrame;
}

void CSlaverDm::reset( const ts_t& ts,const rts_t& rts ){
	log().info(THISMODULE "规约被复位");
	m_wait = false;
	dm::os::protocol::CProtocolSlaver::reset(ts,rts);
}

bool CSlaverDm::setStatusOffset( int offset ){
	if( offset<0 || offset>statusSize() ){
		log().warnning(THISMODULE "无效偏移%d,总数%d",offset,statusSize());
		return false;
	}

	m_offset_s = offset;
	if( m_size_s<0 || (offset+m_size_s)>statusSize() )
		m_size_s = statusSize()-offset;

	return true;
}

bool CSlaverDm::setStatusSize( int size ){
	if( size<0 || (m_offset_s+size)>statusSize() )
		m_size_s = statusSize()-m_offset_s;
	else
		m_size_s = size;

	log().debug(THISMODULE "设置数量%d",m_size_s);

	return true;
}

bool CSlaverDm::setDiscreteOffset( int offset ){
	if( offset<0 ||offset>discreteSize() ){
		log().warnning(THISMODULE "无效偏移%d,总数%d",offset,discreteSize());
		return false;
	}

	m_offset_d = offset;
	if( m_size_d<0 || (offset+m_size_d)>discreteSize() )
		m_size_d = discreteSize()-offset;

	return true;
}

bool CSlaverDm::setDiscreteSize( int size ){
	if( size<0 || (m_offset_d+size)>discreteSize() )
		m_size_d = discreteSize()-m_offset_d;
	else
		m_size_d = size;

	log().debug(THISMODULE "设置数量%d",m_size_d);

	return true;
}

bool CSlaverDm::setMeasureOffset( int offset ){
	if( offset<0 || offset>measureSize() ){
		log().warnning(THISMODULE "无效偏移%d,总数%d",offset,measureSize());
		return false;
	}

	m_offset_m = offset;
	if( m_size_m<0 || (offset+m_size_m)>measureSize() )
		m_size_m = measureSize()-offset;

	return true;
}

bool CSlaverDm::setMeasureSize( int size ){
	if( size<0 || (m_offset_m+size)>measureSize() )
		m_size_m = measureSize()-m_offset_m;
	else
		m_size_m = size;

	log().debug(THISMODULE "设置数量%d",m_size_m);

	return true;
}

bool CSlaverDm::setCumulantOffset( int offset ){
	if( offset<0 || offset>cumulantSize() ){
		log().warnning(THISMODULE "无效偏移%d,总数%d",offset,cumulantSize());
		return false;
	}

	m_offset_c = offset;
	if( m_size_c<0 || (offset+m_size_c)>cumulantSize() )
		m_size_c = cumulantSize()-offset;
	return true;
}

bool CSlaverDm::setCumulantSize( int size ){
	if( size<0 || (m_offset_c+size)>cumulantSize() )
		m_size_c = cumulantSize()-m_offset_c;
	else
		m_size_c = size;

	log().debug(THISMODULE "设置数量%d",m_size_c);

	return true;
}

bool CSlaverDm::setRmtctlOffset( int offset ){
	if( offset<0 || offset>remoteControlSize() ){
		log().warnning(THISMODULE "无效偏移%d,总数%d",offset,remoteControlSize());
		return false;
	}

	m_offset_r = offset;
	if( m_size_r<0 || (offset+m_size_r)>remoteControlSize() )
		m_size_r = remoteControlSize()-offset;
	return true;
}

bool CSlaverDm::setRmtctlSize( int size ){
	if( size<0 || (m_offset_r+size)>remoteControlSize() )
		m_size_r = remoteControlSize()-m_offset_r;
	else
		m_size_r = size;

	log().debug(THISMODULE "设置数量%d",m_size_r);

	return true;
}

bool CSlaverDm::setParameterOffset( int offset ){
	if( offset<0 || offset>parameterSize() ){
		log().warnning(THISMODULE "无效偏移%d,总数%d",offset,parameterSize());
		return false;
	}

	m_offset_p = offset;
	if( m_size_p<0 || (offset+m_size_p)>parameterSize() )
		m_size_p = parameterSize()-offset;
	return true;
}

bool CSlaverDm::setParameterSize( int size ){
	if( size<0 || (m_offset_p+size)>parameterSize() )
		m_size_p = parameterSize()-m_offset_p;
	else
		m_size_p = size;
	
	log().debug(THISMODULE "设置数量%d",m_size_p);

	return true;
}

bool CSlaverDm::setActionOffset( int offset ){
	if( offset<0 || offset>actionSize() ){
		log().warnning(THISMODULE "无效偏移%d,总数%d",offset,actionSize());
		return false;
	}

	m_offset_a = offset;
	if( m_size_a<0 || (offset+m_size_a)>actionSize() )
		m_size_a = actionSize()-offset;
	return true;
}

bool CSlaverDm::setActionSize( int size ){
	if( size<0 || (m_offset_a+size)>actionSize() )
		m_size_a = actionSize()-m_offset_a;
	else
		m_size_a = size;

	log().debug(THISMODULE "设置数量%d",m_size_a);
	return true;
}

CSlaverDm::EAction CSlaverDm::dealRxFrame( const ts_t& ts,const rts_t& rts ){
	m_wait = false;
	enableAnswerMsgCheck(true);
	enableRequestMsgCheck(true);

	dm::os::msg::CMsgInfo msg;

	dm::uint32 start;
	dm::uint16 count;
	dm::CTimeStamp::s_t st;

	switch( m_rxFrame.getFun() ){
	case CFrameDm::Fun_Read_Status:
		if( m_rxFrame.getRead_status(start,count) ){
			log().debug(THISMODULE "收到请求读取状态量 起始%d,个数%d",start,count);
			if( setTask_call(ts,rts,1) ){
				m_ackCall = false;
				m_callIndex = start;
			}
		}
		break;
	case CFrameDm::Fun_Read_Discrete:
		if( m_rxFrame.getRead_discrete(start,count) ){
			log().debug(THISMODULE "收到请求读取离散量 起始%d,个数%d",start,count);
			if( setTask_call(ts,rts,2) ){
				m_ackCall = false;
				m_callIndex = start;
			}
		}
		break;
	case CFrameDm::Fun_Read_Measure:
		if( m_rxFrame.getRead_measure(start,count) ){
			log().debug(THISMODULE "收到请求读取测量量 起始%d,个数%d",start,count);
			if( setTask_call(ts,rts,3) ){
				m_ackCall = false;
				m_callIndex = start;
			}
		}
		break;
	case CFrameDm::Fun_Read_Cumulant:
		if( m_rxFrame.getRead_cumulant(start,count) ){
			log().debug(THISMODULE "收到请求读取累计量 起始%d,个数%d",start,count);
			if( setTask_call(ts,rts,4) ){
				m_ackCall = false;
				m_callIndex = start;
			}
		}

		break;
	case CFrameDm::Fun_Msg:
		if( m_rxFrame.getMsg(msg) ){
			index_t idx;
			switch( msg.getType() ){
			case dm::msg::Msg_RemoteCtl:
				idx = getHostRemoteControlIndex(msg.getRemoteCtl().index);
				if( idx<m_offset_r || idx>=(m_offset_r+m_size_r) ){
					log().warnning(THISMODULE "远控索引号不正确%d offset:%d size:%d",msg.getRemoteCtl().index,m_offset_r,m_size_r);
					return Action_Nothing;
				}else{
					log().debug(THISMODULE "远控消息%d->%d",msg.getRemoteCtl().index,idx);
					msg.getRemoteCtl().index = idx;
				}
				break;
			case dm::msg::Msg_Set:
				idx = getHostParameterIndex(msg.getParaData().index);
				if( idx<m_offset_p || idx>=(m_offset_p+m_size_p) ){
					log().warnning(THISMODULE "设置参数索引号不正确%d offset:%d size:%d",msg.getParaData().index,m_offset_p,m_size_p);
					return Action_Nothing;
				}else{
					log().debug(THISMODULE "设置消息%d->%d",msg.getParaData().index,idx);
					msg.getParaData().index = idx;
				}
				break;
			case dm::msg::Msg_Get:
				idx = getHostParameterIndex(msg.getPara().index);
				if( idx<m_offset_p || idx>=(m_offset_p+m_size_p)  ){
					log().warnning(THISMODULE "读取参数索引号不正确%d offset:%d size:%d",msg.getPara().index,m_offset_p,m_size_p);
					return Action_Nothing;
				}else{
					msg.getPara().index = idx;
				}
				break;
			default:
				break;
			}

			m_msgAgent.sendMsg(msg);
		}

		break;
	case CFrameDm::Fun_Test:
		break;

	case CFrameDm::Fun_Clock:
		if( m_rxFrame.getClock(st) ){
			if( m_acceptClock ){
				dm::CDateTime dt(dm::CTimeStamp(st,0));
				if( dm::CDateTime::setRtc(dt) ){
					log().info(THISMODULE "接受对时 %s 成功",dt.toString().c_str());
				}else{
					log().info(THISMODULE "接受对时 %s 失败",dt.toString().c_str());
				}
			}else{
				log().warnning(THISMODULE "不接受对时");
			}
		}
		break;

	default:
		log().warnning(THISMODULE "未知命令%d",m_rxFrame.getFun());
		break;
	}

	return Action_Nothing;
}

bool CSlaverDm::isWaiting( const rts_t& rts ){
	if( m_wait ){
		if( m_waitTimeout>0 && m_lastRecvTime.isTimeout_sec(m_waitTimeout,rts) ){
			log().warnning(THISMODULE "等待应答超时");
			m_wait = false;
		}
	}

	return m_wait;
}

CSlaverDm::EAction CSlaverDm::taskStart_call( const ts_t& /*ts*/,const rts_t& rts ){
	if( isWaiting(rts) )
		return Action_Nothing;

	int maxIdx;

	switch( m_callGroup ){
	case 1:
		if( m_callIndex<m_offset_s )
			m_callIndex = m_offset_s;
			
		maxIdx = m_offset_s + m_size_s;

		if( m_callIndex>=maxIdx ){
			m_txFrame.setData_status(m_callIndex,0,0);
		}else{
			dm::uint16 count = maxIdx - m_callIndex;
			count = m_txFrame.setData_status(m_callIndex,count);
			for( dm::uint16 i=0;i<count;++i )
				m_txFrame.setData_status(i,statusRt(m_callIndex+i));
		}
		break;
	case 2:
		maxIdx = m_offset_d + m_size_d;

		if( m_callIndex>=maxIdx ){
			m_txFrame.setData_discrete(m_callIndex,0,0);
		}else{
			dm::uint16 count = maxIdx - m_callIndex;
			count = m_txFrame.setData_discrete(m_callIndex,count);
			for( dm::uint16 i=0;i<count;++i )
				m_txFrame.setData_discrete(i,discreteRt(m_callIndex+i));
		}
		break;
	case 3:
		maxIdx = m_offset_m + m_size_m;

		if( m_callIndex>=maxIdx ){
			m_txFrame.setData_measure(m_callIndex,0,0);
		}else{
			dm::uint16 count = maxIdx - m_callIndex;
			count = m_txFrame.setData_measure(m_callIndex,count);
			for( dm::uint16 i=0;i<count;++i )
				m_txFrame.setData_measure(i,measureRt(m_callIndex+i));
		}
		break;
	case 4:
		maxIdx = m_offset_c + m_size_c;

		if( m_callIndex>=maxIdx ){
			m_txFrame.setData_cumulant(m_callIndex,0,0);
		}else{
			dm::uint16 count = maxIdx - m_callIndex;
			count = m_txFrame.setData_cumulant(m_callIndex,count);
			for( dm::uint16 i=0;i<count;++i )
				m_txFrame.setData_cumulant(i,cumulantRt(m_callIndex+i));
		}
		break;
	default:
		m_txFrame.setData_cumulant(m_callIndex,0,0);
		break;
	}


	m_taskCall = None;

	m_wait = true;
	return Action_SendAndReTime;
}

CSlaverDm::EAction CSlaverDm::task_none( const ts_t& ts,const rts_t& rts ){
	dm::os::protocol::CProtocolSlaver::task_none(ts,rts);
	if( isWaiting(rts) )
		return Action_Nothing;

	if( m_clockInterval>0 && m_lastClock.isTimeout_sec(m_clockInterval,rts) ){
		m_lastClock = rts;

		m_txFrame.setClock( ts.seconds() );
		m_wait = true;
		return Action_SendAndReTime;
	}

	EAction act = checkReport(ts,rts);
	if( act!=Action_Nothing )
		return act;

	m_txFrame.setTestAck(true);
	m_wait = true;
	return Action_SendAndReTime;
}

/**
 * 检测是否需要上报数据
 * @param txFrame
 * @return
 */
CSlaverDm::EAction CSlaverDm::checkReport( const ts_t& /*ts*/,const rts_t& rts ){
	if( isWaiting(rts) )
		return Action_Nothing;

	m_txFrame.startAppend_event();

	bool o,f=false;

	dm::scada::CEvent e;
	while( m_em.tryGet(e,o) ){
		if( e.type==dm::scada::CEvent::Status ){
			if( dm::scada::CStatusMgr::ins().size()<=e.idx ){
				log().warnning(THISMODULE "状态量事件，索引%d溢出%d",e.idx,dm::scada::CStatusMgr::ins().size());
				continue;
			}

			// 没有上报时标数据标志，则不上报
			if( !dm::scada::CStatusMgr::ins().info(e.idx)->isFlagReportTimed() )
				continue;
		}else if( e.type==dm::scada::CEvent::Discrete ){
			if( dm::scada::CDiscreteMgr::ins().size()<=e.idx ){
				log().warnning(THISMODULE "离散量事件，索引%d溢出%d",e.idx,dm::scada::CDiscreteMgr::ins().size());
				continue;
			}

			if( !dm::scada::CDiscreteMgr::ins().info(e.idx)->isFlagReportTimed() )
				continue;
		}

		// 如果使用逻辑设备，则转换为逻辑事件
		if( m_logicDevice ){
			if( !m_logicDevice->chg2logicEvent(e) )
				continue;
		}

		// 过滤限值索引
		if( e.type==dm::scada::CEvent::Status ){
			if( e.idx<m_offset_s || e.idx>=(m_offset_s+m_size_s) ){
				log().debug(THISMODULE "状态量索引号%d溢出(%d,%d)",e.idx,m_offset_s,m_size_s);
				continue;
			}
		}else if( e.type==dm::scada::CEvent::Discrete ){
			if( e.idx<m_offset_d || e.idx>=(m_offset_d+m_size_d) )
				continue;
		}else if( e.type==dm::scada::CEvent::Action ){
			if( e.idx<m_offset_a || e.idx>=(m_offset_a+m_size_a) )
				continue;
		}

		f = true;
		if( !m_txFrame.appendEvent(e) ){
			m_wait = true;
			log().info(THISMODULE "发送满帧事件");
			return Action_SendAndReTime;
		}
	}

	if( f ){
		m_wait = true;
		log().info(THISMODULE "发送事件");
		return Action_SendAndReTime;
	}

	m_txFrame.startAppend_timedMeasure();
	dm::scada::CTimedMeasure tm;
	while( m_tm.tryGet(tm,o) ){
		if( dm::scada::CMeasureMgr::ins().size()<=tm.getIndex() ){
			log().warnning(THISMODULE "测量量时标数据，索引%d溢出%d",tm.getIndex(),dm::scada::CMeasureMgr::ins().size());
			continue;
		}

		if( !dm::scada::CMeasureMgr::ins().info(tm.getIndex())->isFlagReportTimed() )
			continue;

		// 逻辑设备过滤
		if( m_logicDevice ){
			if( !m_logicDevice->chg2logicMeasure(tm) )
				continue;
		}

		// 索引号过滤
		if( tm.getIndex()<m_offset_m || tm.getIndex()>=(m_offset_m+m_size_m) )
			continue;

		f = true;
		if( !m_txFrame.appendTimedMeasure(tm) ){
			m_wait = true;
			log().info(THISMODULE "发送满帧测量");
			return Action_SendAndReTime;
		}
	}

	if( f ){
		m_wait = true;
		log().info(THISMODULE "发送测量");
		return Action_SendAndReTime;
	}

	m_txFrame.startAppend_timedCumulant();
	dm::scada::CTimedCumulant tc;
	while( m_tc.tryGet(tc,o) ){
		if( dm::scada::CCumulantMgr::ins().size()<=tc.getIndex() ){
			log().warnning(THISMODULE "累计量时标数据，索引%d溢出%d",tc.getIndex(),dm::scada::CCumulantMgr::ins().size());
			continue;
		}

		if( !dm::scada::CCumulantMgr::ins().info(tc.getIndex())->isFlagReportTimed() )
			continue;

		// 过滤逻辑设备
		if( m_logicDevice ){
			if( !m_logicDevice->chg2logicCumulant(tc) )
				continue;
		}

		// 过滤索引号
		if( tc.getIndex()<m_offset_c || tc.getIndex()>=(m_offset_c+m_size_c) )
			continue;

		f = true;
		if( !m_txFrame.appendTimedCumulant(tc) ){
			m_wait = true;
			log().info(THISMODULE "发送满帧累计");
			return Action_SendAndReTime;
		}
	}

	if( f ){
		m_wait = true;
		log().info(THISMODULE "发送累计");
		return Action_SendAndReTime;
	}

	return Action_Nothing;
}

CSlaverDm::EAction CSlaverDm::onMsgRequest_update( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	msg.getParaData().index = parameterIndex(msg.getParaData().index);
	m_txFrame.setMsg(msg);
	return Action_SendAndReTime;
}

CSlaverDm::EAction CSlaverDm::onMsgAnswer_call( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	m_txFrame.setMsg(msg);
	return Action_SendAndReTime;
}

CSlaverDm::EAction CSlaverDm::onMsgAnswer_rmtCtl( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	msg.getRemoteCtl().index = remoteControlIndex(msg.getRemoteCtl().index);
	m_txFrame.setMsg(msg);
	return Action_SendAndReTime;
}

CSlaverDm::EAction CSlaverDm::onMsgAnswer_set( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	msg.getPara().index = parameterIndex(msg.getPara().index);
	m_txFrame.setMsg(msg);
	return Action_SendAndReTime;
}

CSlaverDm::EAction CSlaverDm::onMsgAnswer_get( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	msg.getParaData().index = parameterIndex(msg.getParaData().index);
	m_txFrame.setMsg(msg);
	return Action_SendAndReTime;
}

CSlaverDm::EAction CSlaverDm::onMsgAnswer_syncData( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	m_txFrame.setMsg(msg);
	return Action_SendAndReTime;
}

CSlaverDm::EAction CSlaverDm::onMsgAnswer_remoteReset( dm::os::msg::CMsgInfo& msg,const ts_t& /*ts*/,const rts_t& /*rts*/ ){
	m_txFrame.setMsg(msg);
	return Action_SendAndReTime;
}
